package com.easy.aop;

import com.alibaba.fastjson2.JSON;
import com.easy.bean.OperationLog;
import com.easy.service.OperationLogService;
import com.easy.util.TokenUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class OperationLogAspect {
    
    @Autowired
    private OperationLogService operationLogService;
    
    // 定义切点，拦截所有Controller中带有REST相关注解的方法
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.PutMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.DeleteMapping) || " +
              "@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void operationLogPointcut() {
    }
    
    @Around("operationLogPointcut()")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        OperationLog operationLog = new OperationLog();
        
        try {
            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            
            // 获取控制器类名
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String tableName = extractTableName(className);
            
            // 确保tableName不为null或空
            if (tableName == null || tableName.isEmpty()) {
                tableName = "unknown_table";
            }
            
            // 获取操作类型
            String operationType = getOperationType(method);
            
            // 只记录增删改操作，不记录查询操作
            if ("SELECT".equals(operationType) || "UNKNOWN".equals(operationType)) {
                // 直接执行原方法，不记录日志
                return joinPoint.proceed();
            }
            
            operationLog.setTableName(tableName);
            operationLog.setOperationType(operationType != null ? operationType : "UNKNOWN");
            operationLog.setOperator(getCurrentUser());
            operationLog.setOperationTime(new Date());
            
            // 获取方法参数
            Object[] args = joinPoint.getArgs();
            if (args.length > 0) {
                // 尝试获取ID参数（用于更新和删除操作）
                for (Object arg : args) {
                    if (arg != null) {
                        // 如果参数中有ID字段，记录ID
                        try {
                            Integer id = (Integer) arg.getClass().getMethod("getId").invoke(arg);
                            if (id != null) {
                                operationLog.setRecordId(id);
                                // 如果是更新操作，记录旧值
                                if ("UPDATE".equals(operationType)) {
                                    operationLog.setOldValue(JSON.toJSONString(arg));
                                }
                                break;
                            }
                        } catch (Exception e) {
                            // 忽略异常，继续处理其他参数
                        }

                        // 如果是更新操作，记录新值
                        if ("UPDATE".equals(operationType)) {
                            operationLog.setNewValue(JSON.toJSONString(arg));
                        }
                    }
                }
            }
            
            // 执行原方法
            result = joinPoint.proceed();

            // 获取操作后的对象值（更新后的值）
            if ("UPDATE".equals(operationType) && operationLog.getRecordId() != null) {
                operationLog.setNewValue(JSON.toJSONString(result)); // 假设返回值为更新后的对象
            }

            // 记录操作描述，包含具体的SQL语句信息
            String description = buildOperationDescription(operationType, tableName, operationLog.getRecordId());
            operationLog.setDescription(description);
            
            // 保存日志
            try {
                operationLogService.add(operationLog);
            } catch (Exception e) {
                // 日志记录失败不应该影响主业务流程
                System.err.println("操作日志记录失败: " + e.getMessage());
            }
            
        } catch (Exception e) {
            // 发生异常时也记录日志
            // 确保关键字段不为null
            if (operationLog.getTableName() == null || operationLog.getTableName().isEmpty()) {
                operationLog.setTableName("unknown_table");
            }
            
            if (operationLog.getOperationType() == null) {
                operationLog.setOperationType("UNKNOWN");
            }
            
            operationLog.setDescription("操作执行异常: " + e.getMessage());
            try {
                operationLogService.add(operationLog);
            } catch (Exception logException) {
                // 日志记录失败不应该影响主业务流程
                System.err.println("操作日志记录失败: " + logException.getMessage());
            }
            throw e; // 重新抛出异常
        }
        
        return result;
    }
    
    /**
     * 构建操作描述信息
     * @param operationType 操作类型
     * @param tableName 表名
     * @param recordId 记录ID
     * @return 描述信息
     */
    private String buildOperationDescription(String operationType, String tableName, Integer recordId) {
        StringBuilder description = new StringBuilder();
        description.append("对表 ").append(tableName).append(" 执行 ").append(operationType != null ? operationType : "UNKNOWN").append(" 操作");

        if (recordId != null) {
            description.append("，记录ID: ").append(recordId);
        }

        return description.toString();
    }
    
    /**
     * 从类名中提取表名
     */
    private String extractTableName(String className) {
        // 移除"Controller"后缀
        if (className != null && className.endsWith("Controller")) {
            return className.substring(0, className.length() - 10).toLowerCase();
        }
        return className != null ? className.toLowerCase() : "unknown_table";
    }
    
    /**
     * 根据方法上的注解判断操作类型
     */
    private String getOperationType(Method method) {
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        PutMapping putMapping = method.getAnnotation(PutMapping.class);
        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        
        if (postMapping != null) {
            return "INSERT";
        } else if (putMapping != null || isPutRequest(requestMapping)) {
            return "UPDATE";
        } else if (deleteMapping != null || isDeleteRequest(requestMapping)) {
            return "DELETE";
        } else if (getMapping != null) {
            return "SELECT";
        } else {
            // 从RequestMapping的method属性判断
            if (requestMapping != null && requestMapping.method().length > 0) {
                for (RequestMethod requestMethod : requestMapping.method()) {
                    switch (requestMethod) {
                        case POST:
                            return "INSERT";
                        case PUT:
                            return "UPDATE";
                        case DELETE:
                            return "DELETE";
                        case GET:
                            return "SELECT";
                    }
                }
            }
        }
        return "UNKNOWN";
    }
    
    /**
     * 判断是否为PUT请求
     */
    private boolean isPutRequest(RequestMapping requestMapping) {
        if (requestMapping != null && requestMapping.method().length > 0) {
            for (RequestMethod method : requestMapping.method()) {
                if (method == RequestMethod.PUT) {
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * 判断是否为DELETE请求
     */
    private boolean isDeleteRequest(RequestMapping requestMapping) {
        if (requestMapping != null && requestMapping.method().length > 0) {
            for (RequestMethod method : requestMapping.method()) {
                if (method == RequestMethod.DELETE) {
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * 获取当前操作用户
     */
    private String getCurrentUser() {
        try {
            // 尝试从Token中获取用户信息
            return TokenUtil.getCurrentUser();
        } catch (Exception e) {
            return "system"; // 默认用户
        }
    }
}